{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "import pandas as pd\n",
    "import numpy as np\n",
    "import sunpy"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "qkl_hc = pd.read_csv('./cdaw_cactus_lz_halo_integrated.csv', parse_dates=['Timestamp', 'cactus_ts'])\n",
    "qkl_c = pd.read_csv('./cdaw_cactus_lz_nonhalo_integrated.csv', parse_dates=['Timestamp', 'cactus_ts'])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "qkl = qkl_hc.append(qkl_c, ignore_index=True)\n",
    "qkl = qkl.rename(columns={'Unnamed: 0':'id'}).set_index('id')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [],
   "source": [
    "flares = pd.read_csv('./fl_assoc/soho_goes_flares.csv', index_col=0, parse_dates=['start_time', 'peak_time', 'end_time'])\n",
    "# fl12 = flares[ (flares['end_time'] < '2013-01-01' ) & (flares['start_time'] > '2011-12-31T23:00' )]\n",
    "fl12 = flares\n",
    "\n",
    "flc12 = fl12[ fl12['goes_class'] > 'C']"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<class 'pandas.core.frame.DataFrame'>\n",
      "Index: 14755 entries, gid_soho_0 to gid_soho_14758\n",
      "Data columns (total 28 columns):\n",
      " #   Column                Non-Null Count  Dtype         \n",
      "---  ------                --------------  -----         \n",
      " 0   noaa_active_region    6037 non-null   float64       \n",
      " 1   event_date            14755 non-null  object        \n",
      " 2   start_time            14755 non-null  datetime64[ns]\n",
      " 3   peak_time             14755 non-null  datetime64[ns]\n",
      " 4   goes_class            14755 non-null  object        \n",
      " 5   goes_location         14755 non-null  object        \n",
      " 6   Unnamed: 7            0 non-null      float64       \n",
      " 7   end_time              14755 non-null  datetime64[ns]\n",
      " 8   start_time_detection  4542 non-null   object        \n",
      " 9   end_time_detection    4542 non-null   object        \n",
      " 10  eit_location          4542 non-null   object        \n",
      " 11  fl_location           6162 non-null   object        \n",
      " 12  y                     6157 non-null   float64       \n",
      " 13  x                     6157 non-null   float64       \n",
      " 14  centroids             5976 non-null   object        \n",
      " 15  fl_lat                6158 non-null   float64       \n",
      " 16  fl_lon                6158 non-null   float64       \n",
      " 17  x_hpc                 6158 non-null   float64       \n",
      " 18  y_hpc                 6158 non-null   float64       \n",
      " 19  hinode_fl_id          267 non-null    float64       \n",
      " 20  hinode_verified       14755 non-null  bool          \n",
      " 21  hinode_x_hpc          267 non-null    float64       \n",
      " 22  hinode_y_hpc          267 non-null    float64       \n",
      " 23  eit_lon               4542 non-null   object        \n",
      " 24  eit_lat               4542 non-null   float64       \n",
      " 25  eit_x_hpc             4542 non-null   float64       \n",
      " 26  eit_y_hpc             4542 non-null   float64       \n",
      " 27  eit_verified          14755 non-null  bool          \n",
      "dtypes: bool(2), datetime64[ns](3), float64(14), object(9)\n",
      "memory usage: 3.1+ MB\n"
     ]
    }
   ],
   "source": [
    "flc12.info()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [],
   "source": [
    "# qkl_12 = qkl[ (qkl['Timestamp'] < '2013-01-01' ) & (qkl['Timestamp'] > '2011-12-31' )]\n",
    "qkl_12 = qkl"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<class 'pandas.core.frame.DataFrame'>\n",
      "Index: 14072 entries, lasco_14901 to lz_10140\n",
      "Data columns (total 25 columns):\n",
      " #   Column                      Non-Null Count  Dtype         \n",
      "---  ------                      --------------  -----         \n",
      " 0   Timestamp                   10506 non-null  datetime64[ns]\n",
      " 1   Central_PA                  10506 non-null  float64       \n",
      " 2   Width                       10506 non-null  float64       \n",
      " 3   Linear_Speed                10506 non-null  float64       \n",
      " 4   2nd_order_speed_initial     10260 non-null  float64       \n",
      " 5   2nd_order_speed_final       10260 non-null  float64       \n",
      " 6   2nd_order_speed_20R         10260 non-null  float64       \n",
      " 7   Accel                       10260 non-null  float64       \n",
      " 8   Mass                        7175 non-null   float64       \n",
      " 9   Kinetic_Energy              7175 non-null   float64       \n",
      " 10  MPA                         10506 non-null  float64       \n",
      " 11  Remarks                     5127 non-null   object        \n",
      " 12  Acceleration_uncertainty    10506 non-null  object        \n",
      " 13  Kinetic_Energy_uncertainty  10506 non-null  object        \n",
      " 14  Mass_uncertainty            10506 non-null  object        \n",
      " 15  cactus_id                   8108 non-null   object        \n",
      " 16  lz_td                       4542 non-null   float64       \n",
      " 17  lz_pad                      4542 non-null   float64       \n",
      " 18  lz_wd                       4542 non-null   float64       \n",
      " 19  lz_vd                       4542 non-null   float64       \n",
      " 20  cactus_pa                   8108 non-null   float64       \n",
      " 21  cactus_da                   8108 non-null   float64       \n",
      " 22  cactus_v                    8108 non-null   float64       \n",
      " 23  lz_tot_de                   4542 non-null   float64       \n",
      " 24  cactus_ts                   3566 non-null   datetime64[ns]\n",
      "dtypes: datetime64[ns](2), float64(18), object(5)\n",
      "memory usage: 2.8+ MB\n"
     ]
    }
   ],
   "source": [
    "qkl_12.info()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [],
   "source": [
    "from astropy.coordinates import SkyCoord\n",
    "import astropy.units as u\n",
    "from sunpy.coordinates import frames\n",
    "\n",
    "def calculate_fl_pa_CCWNP(fl_lon, fl_lat, obs_time='2012-01-01'):\n",
    "    fl_hgs = SkyCoord(fl_lon*u.deg, fl_lat*u.deg, frame=frames.HeliographicStonyhurst, observer=\"earth\", obstime=obs_time)\n",
    "    fl_hpc = fl_hgs.transform_to(frames.Helioprojective)\n",
    "    hpc_x = fl_hpc.Tx.value\n",
    "    hpc_y = fl_hpc.Ty.value\n",
    "\n",
    "# Quadrants for finding approx. flare principle angle using HPC.\n",
    "# The returned PA values starts from North and goes counter clockwise\n",
    "#      _____N_____  \n",
    "#     |     |     |\n",
    "#     |  Q2 |  Q1 |\n",
    "#     E-----|-----W\n",
    "#     |  Q3 |  Q4 |\n",
    "#     |_____S_____|\n",
    "    \n",
    "    if hpc_x > 0 and hpc_y > 0: #Q1\n",
    "#         print('Q1')\n",
    "        return 360 - np.rad2deg( np.arctan( hpc_x / hpc_y ) )\n",
    "    elif hpc_x > 0 and hpc_y < 0: # Q4\n",
    "#         print('Q4', np.rad2deg( np.arctan( hpc_x / np.abs(hpc_y) ) ))\n",
    "        return 180 + np.rad2deg( np.arctan( hpc_x / np.abs(hpc_y) ) )\n",
    "    elif hpc_x < 0 and hpc_y > 0: # Q2\n",
    "#         print('Q2')\n",
    "        return np.rad2deg( np.arctan( np.abs(hpc_x) / hpc_y ) )\n",
    "    elif hpc_x < 0 and hpc_y < 0: # q3\n",
    "#         print('Q3')\n",
    "        return 180 - np.rad2deg( np.arctan( hpc_x / hpc_y ) )\n",
    "    else:\n",
    "        if hpc_y == 0 and hpc_x == 0:\n",
    "            return np.nan\n",
    "        elif hpc_x == 0:\n",
    "            if hpc_y > 0:\n",
    "                return 0\n",
    "            else:\n",
    "                return 180\n",
    "        elif hpc_y == 0:\n",
    "            if hpc_x > 0:\n",
    "                return 270\n",
    "            else:\n",
    "                return 90\n",
    "\n",
    "def calculate_hc_angle(lat, cmd, ref_lat=0, ref_cmd=0):\n",
    "    # Calculates the great circle distance (central angle) between\n",
    "    # lat is latitude\n",
    "    # cmd is longitude/central meridian dist\n",
    "    # ref_lat: reference latitude, default from center, 0\n",
    "    # ref_cmd: reference cmd, default from center, 0\n",
    "    # On the surface of a sphere with radius r\n",
    "    # INPUT UNIT: DEGREES\n",
    "    lat = lat * np.pi / 180\n",
    "    cmd = cmd * np.pi / 180\n",
    "    \n",
    "    ref_lat = ref_lat * np.pi / 180\n",
    "    ref_cmd = ref_cmd * np.pi / 180\n",
    "    \n",
    "    \n",
    "    dlong = cmd - ref_cmd\n",
    "    den = np.sin(lat) * np.sin(ref_lat) + np.cos(lat) * np.cos(ref_lat) * np.cos(dlong)\n",
    "    num = (np.cos(ref_lat) * np.sin(dlong)) ** 2 + (\n",
    "            np.cos(lat) * np.sin(ref_lat) - np.sin(lat) * np.cos(ref_lat) * np.cos(dlong)) ** 2\n",
    "    # Calculate the great circle distance:\n",
    "    sig = np.arctan2(np.sqrt(num), den) * 180 / np.pi\n",
    "    return sig\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "def calculate_hc_angle2(cmd, lat):\n",
    "    # calculates central angle (mu) --> from heliographic central meridian distance (cmd) and latitude (lat)\n",
    "    cmd = cmd * np.pi / 180\n",
    "    lat = lat * np.pi / 180\n",
    "    return np.rad2deg ( np.arccos(np.cos(cmd)*np.cos(lat)) )\n",
    "\n",
    "# print( calculate_hc_angle2(30, 30) )\n",
    "\n",
    "def calculate_fl_psi_CCWNP(lat, cmd):\n",
    "    # Calculates the flare position angle as described in Youssef (2012) - https://doi.org/10.1016/j.nrjag.2012.12.014\n",
    "    # lat is latitude\n",
    "    # cmd is longitude/central meridian dist\n",
    "    lat = lat * np.pi / 180\n",
    "    cmd = cmd * np.pi / 180\n",
    "    \n",
    "    # Quadrants for finding approx. flare principle angle using HPC.\n",
    "    # The returned PA values starts from North and goes counter clockwise\n",
    "    #      _____N_____  \n",
    "    #     |     |     |\n",
    "    #     |  Q2 |  Q1 |\n",
    "    #     E-----|-----W --- E-W for CMD/ N-S for Lat\n",
    "    #     |  Q3 |  Q4 |\n",
    "    #     |_____S_____|\n",
    "    \n",
    "    if lat == 0:\n",
    "        if cmd == 0:\n",
    "            return np.nan\n",
    "        elif cmd < 0:\n",
    "            return 90\n",
    "        elif cmd > 0:\n",
    "            return 270\n",
    "    \n",
    "    if cmd >= 0 and lat > 0: # Q1\n",
    "        return 360 - np.rad2deg( np.arctan(np.sin(cmd)/np.tan(lat)) )\n",
    "    elif cmd < 0 and lat > 0: # Q2\n",
    "        return -np.rad2deg( np.arctan(np.sin(cmd)/np.tan(lat)) )\n",
    "    elif cmd >= 0 and lat < 0: # Q4\n",
    "        return 180 + np.rad2deg( np.arctan(np.sin(cmd)/np.tan(-lat)) )\n",
    "    elif cmd < 0 and lat < 0: # Q3\n",
    "        return 180 - np.rad2deg( np.arctan(np.sin(cmd)/np.tan(lat)) )\n",
    "    \n",
    "    \n",
    "#test cases\n",
    "# print( calculate_fl_psi_CCWNP(lat=25, cmd=30) ) ## ~313\n",
    "# print( calculate_fl_psi_CCWNP(lat=-25, cmd=30) ) ## ~227\n",
    "# print( calculate_fl_psi_CCWNP(lat=45, cmd=-20) ) ## ~19\n",
    "# print( calculate_fl_psi_CCWNP(lat=-60, cmd=-30) ) ## ~196\n",
    "# print( calculate_fl_psi_CCWNP(lat=-90, cmd=0) ) ## ~180\n",
    "# print( calculate_fl_psi_CCWNP(lat=0, cmd=-80) ) ## ~90\n",
    "# print( calculate_fl_psi_CCWNP(lat=0, cmd=90) ) ## ~270\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "10.285618126647172"
      ]
     },
     "execution_count": 11,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "calculate_hc_angle2(5, 9)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [],
   "source": [
    "def goes_class_to_peak_flux(gclass):\n",
    "    category = gclass[0]\n",
    "    factor = float(gclass[1:])\n",
    "    \n",
    "    if category == 'A':\n",
    "        return factor * 10**-8\n",
    "    elif category == 'B':\n",
    "        return factor * 10**-7\n",
    "    elif category == 'C':\n",
    "        return factor * 10**-6\n",
    "    elif category == 'M':\n",
    "        return factor * 10**-5\n",
    "    elif category == 'X':\n",
    "        return factor * 10**-4\n",
    "    else:\n",
    "        return np.nan\n",
    "    \n",
    "# goes_class_to_peak_flux('M3.8')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [],
   "source": [
    "def search_cme_temporal(cme_df, cme_ts_col_name, start, end):\n",
    "    return cme_df[(cme_df[cme_ts_col_name] > start) & (cme_df[cme_ts_col_name] < end)]\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [],
   "source": [
    "#create cme to flare association dictionary\n",
    "def create_cme2fl(qkl_12):\n",
    "    cme2fl = dict()\n",
    "    for lasco_id in qkl_12.index:\n",
    "        cme2fl[lasco_id] = []\n",
    "    return cme2fl"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [],
   "source": [
    "def get_difference_angle(cme_pa, fl_pa):\n",
    "    diff_a = -1\n",
    "#     print(cme_pa, fl_pa)\n",
    "    if np.abs(cme_pa - fl_pa) <= 180:\n",
    "        diff_a = np.abs(cme_pa - fl_pa)\n",
    "    else:\n",
    "        diff_a = 360 - (max(cme_pa, fl_pa) - min(cme_pa, fl_pa)) \n",
    "    return diff_a\n",
    "\n",
    "def get_new_conf_criteria(n=5):\n",
    "    return [False] * n\n",
    "\n",
    "def check_confidence_criterion_temporal(result_df):\n",
    "    # check if there exists a match\n",
    "    return result_df.shape[0] > 0\n",
    "\n",
    "def check_confidence_criterion_1to1(result_df):\n",
    "    # check if there exists only one match\n",
    "    return result_df.shape[0] == 1\n",
    "\n",
    "def check_confidence_criterion_1to1_cme(result_df, fl_df):\n",
    "    # check if there exists only one match\n",
    "    if result_df.shape[0] == 1:\n",
    "        cme_candidate = result_df.iloc[0]\n",
    "        cme_onset = cme_candidate['Timestamp']\n",
    "        \n",
    "        search_start_time = cme_onset - np.timedelta64(1, 'h')\n",
    "        search_end_time = cme_onset + np.timedelta64(1, 'h')\n",
    "        \n",
    "#         flstart-1h < cmeonset < flpeak + 1h\n",
    "#         send = cmeonset + 1h > flstart\n",
    "#         sstart =cmeonset - 1h < flpeak\n",
    "        \n",
    "#         print(fl_df[ (fl_df['start_time'] <= search_end_time) & (fl_df['peak_time'] >= search_start_time) ] )\n",
    "        if fl_df[ (fl_df['start_time'] <= search_end_time) & (fl_df['peak_time'] >= search_start_time) ].shape[0] == 1:\n",
    "            return True # there is only one flare candidate for only CME\n",
    "        else:\n",
    "            return False # there are more than one flare candidates for the CME candidate\n",
    "    else: # There are more than ne cme candidates\n",
    "        return False\n",
    "\n",
    "    \n",
    "# def check_confidence_criterion_flpa_hpc(cme_candidate, fl_pa_hpc):\n",
    "#     if fl_pa_hpc is None:\n",
    "#         return False\n",
    "#     mpa = cme_candidate['MPA']\n",
    "#     width = cme_candidate['Width']\n",
    "#     diff_a = get_difference_angle(mpa, fl_pa_hpc)\n",
    "    \n",
    "#     if diff_a <= max(60, width):\n",
    "#         return True\n",
    "#     else:\n",
    "#         return False\n",
    "    \n",
    "def check_confidence_criterion_hard_threshold(cme_candidate, fl_lon, fl_lat, fl_pa_radial, threshold=60):\n",
    "    if fl_pa_radial is None:\n",
    "        return False\n",
    "    if calculate_hc_angle2(fl_lon, fl_lat) < 10:\n",
    "        return False\n",
    "    mpa = cme_candidate['MPA']\n",
    "    width = cme_candidate['Width']\n",
    "    diff_a = get_difference_angle(mpa, fl_pa_radial)\n",
    "    \n",
    "    if diff_a <= threshold:\n",
    "        return True\n",
    "    else:\n",
    "        return False\n",
    "\n",
    "def check_confidence_criterion_quadrant(cme_candidate, fl_lon, fl_lat, fl_pa_radial):\n",
    "    if fl_pa_radial is None:\n",
    "        return False\n",
    "    if calculate_hc_angle2(fl_lon, fl_lat) < 10:\n",
    "        return False\n",
    "    mpa = cme_candidate['MPA']\n",
    "    \n",
    "    diff_a = get_difference_angle(mpa, fl_pa_radial)\n",
    "    if diff_a < 8:\n",
    "        return True\n",
    "    else:\n",
    "        cme_q = mpa // 90\n",
    "        fl_q = fl_pa_radial // 90\n",
    "        if fl_q == cme_q:\n",
    "            return True\n",
    "        else:\n",
    "            return False\n",
    "\n",
    "    \n",
    "def check_confidence_criterion_hcangle_flpa(cme_candidate, fl_lon, fl_lat, fl_pa_radial):\n",
    "    if fl_pa_radial is None:\n",
    "        return False\n",
    "    \n",
    "    if calculate_hc_angle2(fl_lon, fl_lat) < 10:\n",
    "        return False\n",
    "    else:\n",
    "        mpa = cme_candidate['MPA']\n",
    "        width = cme_candidate['Width']\n",
    "        diff_a = get_difference_angle(mpa, fl_pa_radial)\n",
    "\n",
    "        if diff_a <= width:\n",
    "            return True\n",
    "        else:\n",
    "            return False"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [],
   "source": [
    "cme2fl = create_cme2fl(qkl_12)\n",
    "\n",
    "count = 0\n",
    "count2p = 0\n",
    "diff_angle_90p = 0\n",
    "\n",
    "\n",
    "pd.options.mode.chained_assignment = None  # default='warn'\n",
    "# flc_copy = flc12.copy()\n",
    "\n",
    "flc12['cme_id'] ='' \n",
    "flc12.reindex(flc12.columns.tolist() + ['fl_pa', 'cme_mpa', 'cme_vel', 'cme_width', 'cme_assoc_conf', 'diff_a'], axis=1)\n",
    "\n",
    "for i,row in flc12.iterrows():\n",
    "    \n",
    "    search_start_time = row['start_time'] - np.timedelta64(30, 'm')\n",
    "    search_end_time = row['peak_time'] + np.timedelta64(1, 'h')\n",
    "    res = search_cme_temporal(qkl_12, 'Timestamp', search_start_time, search_end_time)\n",
    "    \n",
    "    \n",
    "    if res.shape[0] > 0:\n",
    "        #print(i, row['start_time'], row['goes_class'], search_start_time, search_end_time, row['fl_lon'], row['fl_lat'] )\n",
    "        #print(fl_pa, res['Central_PA'].values[0], res['Width'].values[0])\n",
    "        fl_pa = calculate_fl_pa_CCWNP(row['fl_lon'], row['fl_lat'], row['start_time']) \n",
    "        fl_psi = calculate_fl_psi_CCWNP(row['fl_lat'], row['fl_lon']) \n",
    "        \n",
    "        if fl_pa is None:\n",
    "            continue\n",
    "        \n",
    "        conf_scores = [0] * res.shape[0]\n",
    "        \n",
    "        ji = 0\n",
    "        for j, cme_row in res.iterrows():\n",
    "            conf = get_new_conf_criteria(n=5)\n",
    "            conf[0] = True # there is a temporal match\n",
    "            conf[1] = check_confidence_criterion_1to1_cme(res, flc12) # check if there is only one match\n",
    "            conf[2] = check_confidence_criterion_quadrant(cme_row, row['fl_lon'], row['fl_lat'], fl_psi)\n",
    "            conf[3] = check_confidence_criterion_hard_threshold(cme_row, row['fl_lon'], row['fl_lat'], fl_psi)\n",
    "            conf[4] = check_confidence_criterion_hcangle_flpa(cme_row, row['fl_lon'], row['fl_lat'], fl_psi)\n",
    "            \n",
    "#             print(conf)\n",
    "            conf_scores[ji] = sum(conf)\n",
    "            ji += 1\n",
    "            \n",
    "        \n",
    "        conf_scores = np.asarray(conf_scores)\n",
    "        max_conf_score = np.max(conf_scores)\n",
    "        filtered = res[ conf_scores == max_conf_score ]\n",
    "\n",
    "        if np.sum( conf_scores == np.max(conf_scores) ) == 1: # get the CME with highest confidence score\n",
    "            result = filtered.iloc[0]\n",
    "        elif np.sum( conf_scores == np.max(conf_scores) ) > 1:\n",
    "            diff_angles = [] # this is the tie breaker\n",
    "            for j, cme_row in filtered.iterrows():\n",
    "                diff_a = get_difference_angle(cme_row['MPA'], fl_psi)\n",
    "                diff_angles.append(diff_a)\n",
    "\n",
    "            result = filtered.iloc[diff_angles.index(min(diff_angles))]\n",
    "#             print(result)    \n",
    "\n",
    "        cme_id = result.name\n",
    "        cme2fl[cme_id].append( (i, max_conf_score) )\n",
    "        flc12.at[i, 'fl_pa'] = fl_psi\n",
    "        flc12.at[i, 'cme_id'] = cme_id\n",
    "        flc12.at[i, 'cme_mpa'] = result['MPA']\n",
    "        flc12.at[i, 'diff_a'] = get_difference_angle(fl_psi, result['MPA'])\n",
    "        flc12.at[i, 'cme_vel'] = result['Linear_Speed']\n",
    "        flc12.at[i, 'cme_width'] = result['Width']\n",
    "        flc12.at[i, 'cme_assoc_conf'] = max_conf_score\n",
    "\n",
    "flc12.to_csv('fl2cme_soho.csv')\n",
    "#         print('\\n')\n",
    "#         break\n",
    "# print(count, count2p, diff_angle_90p, flc12.shape[0] )"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "jupyter": {
     "outputs_hidden": true
    }
   },
   "outputs": [],
   "source": [
    "for key,value in cme2fl.items():\n",
    "    print(key, len(value), value )"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "flc12"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "count = 0\n",
    "count0 = 0\n",
    "count1 = 0\n",
    "for key,value in cme2fl.items():\n",
    "    if len(value)>1:\n",
    "        count = count+1\n",
    "    elif len(value) == 0:\n",
    "        count0 = count0+1\n",
    "    else:\n",
    "        count1 = count1+1\n",
    "    \n",
    "print(count0, count1, count )"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.6"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
